package com.mobilottery.server;

import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.util.AbstractMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.log4j.Logger;

/**
 * Helper class to access properties in configuration file
 * @author fedor
 */
public class ConfManager {

	public static final String PROPERTY_LOTTERY_SYSTEM_IMPL = "mobilottery.lotterysystem.implementation";
	
	private static ConfManager instance = null;

	private final static String defaultConfigFilename = "lottery.properties";
	private File configFile;
	private long lastConfigChange;
	private Properties configData = null;
	static Logger log = Logger.getLogger(ConfManager.class);


	public synchronized static ConfManager getInstance()
	{
		if(instance==null) {
			instance=new ConfManager();
			instance.initConfigFile();
		}
		return instance;
	}

	public static ConfManager getlocalConfig(String filePath)
	{
		if(instance==null) {
			instance=new ConfManager();
			instance.configFile = new File(filePath);
		}
		return instance;
	}

	private ConfManager()
	{
	}

	void initConfigFile()
	{
		URL configURL = getClass().getClassLoader().getResource(defaultConfigFilename);
		if (configURL != null)
		{
			configFile = new File(configURL.getPath().replace("%20", " "));
			log.info("looking configuration in " + configFile.getAbsolutePath() + (!configFile.exists() ? " - no file found" : " - found properties file"));
			
		}
		else
		{
			log.error("no configuration found");
			configFile = null;
			throw new RuntimeException("file configuration not found.");
		}
	}


	public boolean hasConfig()
	{
		return configFile != null && configFile.exists();
	}

	public File getConfigFile() {
		return configFile;
	}

	public void setConfigFile(String filename) {
    	configFile = new File(filename);
		if (!configFile.exists()) {
			configFile = null;
		}

	}

//	public String getRawProperty(String key) {
//		reloadProperties();
//		return mGetRawProperty(key);
//	}

	/**
	 * Returns property value
	 * @param key property key
	 * @return property value
	 */
	public String getProperty(String key)
	{
		reloadProperties();
		return mGetRawProperty(key);
	}
	
	/**
	 * Returns property value
	 * @param key property key
	 * @param defaultValue default value to return if no property was found under the key
	 * @return property value
	 */
	public String getProperty(String key, String defaultValue)
	{
		reloadProperties();
		if(configData.containsKey(key)) return mGetRawProperty(key);
		return defaultValue;
	}	

	Map<String, String> propertyMap = new AbstractMap<String, String>()
	{

		@Override
		public Set<java.util.Map.Entry<String, String>> entrySet() {
			throw new UnsupportedOperationException();
		}

		public String get(Object key)
		{
			return getProperty(key!=null ? key.toString() : null);
		}


	};

	public Map<String, String> getProperties()
	{
		return propertyMap;
	}

	public boolean hasProperty(String key)
	{
		return getProperty(key) != null;
	}


	public void setAlternateConfig(File alternateFile) {
		configFile = alternateFile;
		configData = null;
		lastConfigChange = 0;
	}


	private void loadProperties()
	{
		configData= new Properties();
		try {
			FileInputStream inputProperties = null;
			if(configFile==null)
			{
				initConfigFile();
			}
			if(configFile!=null)
			{
				try
				{
					inputProperties = new FileInputStream(configFile);
					configData.load(inputProperties);
					lastConfigChange = configFile.lastModified();
				}
				finally
				{
					if (inputProperties != null)
						inputProperties.close();
				}
			}
			else
			{
				log.error("no configuraiton found");
			}
		}
		catch (Throwable e)
		{
			log.error("error loading configuration properties", e);
			throw new RuntimeException(e);
		}
	}


	private void reloadProperties()
	{
		if (!hasConfig() || lastConfigChange < configFile.lastModified())
		{
			loadProperties();
			if(configData==null)
				configData= new Properties();
		}
	}

	private String mGetRawProperty(String key) {
		return configData.getProperty(key);
	}
	
}
